package com.teach.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.teach.dto.IdDto;
import com.teach.entity.ResponseEntity;
import com.teach.entity.TbDraw;
import com.teach.entity.TbSeckillOrders;
import com.teach.entity.TbSeckillgoods;
import com.teach.mapper.TbDrawMapper;
import com.teach.mapper.TbSeckillOrdersMapper;
import com.teach.mapper.TbSeckillgoodsMapper;
import com.teach.service.SeckillService;
import com.teach.utils.IdWorker;
import com.teach.utils.RedisUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Transactional
@Service
public class SeckillServiceImpl implements SeckillService {
    Logger logger= LogManager.getLogger();
    @Resource
    TbSeckillgoodsMapper tbSeckillgoodsMapper;
    @Resource
    Redisson redisson;
    @Resource
    IdWorker idWorker;
    @Resource
    RedisUtils redisUtils;
    @Value("${seckill.object.key}")
    String seckillKey;
    @Resource
    TbDrawMapper tbDrawMapper;
    @Resource
    TbSeckillOrdersMapper tbSeckillOrdersMapper;
    @Resource
    RabbitTemplate rabbitTemplate;

    @Override
    public void addRedis() {
        //获取秒杀数据
        List<TbSeckillgoods> seckillgoodsList = tbSeckillgoodsMapper.selectList(null);
        //将秒杀数据循环存放到redis中
        seckillgoodsList.stream().forEach(seckillgoods ->{
            redisUtils.setBoundHash(seckillKey,seckillgoods.getId(),seckillgoods);
        });
    }

    @Override
    public ResponseEntity seckillGoods(IdDto idDto, String token) {
        Boolean flag=false;
        Integer id=idDto.getCourseId();
        Integer did=idDto.getDrawId();
        BigDecimal price = null;
        RLock lock = redisson.getLock("seckill:goods"+id);
        //自定义时间
        /*lock.lock(3, TimeUnit.MINUTES);*/
        //解析token
        Claims claims = Jwts.parser().setSigningKey("huangyujie").parseClaimsJws(token).getBody();
        Integer uid=Integer.parseInt(claims.getId());
        //根据商品id查询出该商品
        TbSeckillgoods seckillgoods = tbSeckillgoodsMapper.selectById(id);
        //判断秒杀时间
        if(seckillgoods.getStartTime().isAfter(LocalDateTime.now())){
            return new ResponseEntity(null,500,"秒杀还没开始",false);
        }
        if(seckillgoods.getEndTime().isBefore(LocalDateTime.now())){
            return new ResponseEntity(null,500,"秒杀已经结束",false);
        }
        try {
            //根据商品id获取redis中所对应的数据
            Object boundHash = redisUtils.getBoundHash(seckillKey, id);
            if(boundHash == null){
                return new ResponseEntity(null,500,"该商品不存在",false);
            }
            TbSeckillgoods tbSeckillgoods=null;
            if(boundHash instanceof TbSeckillgoods){
                tbSeckillgoods= (TbSeckillgoods) boundHash;
            }
            //判断该商品的库存
            if(tbSeckillgoods.getNum()<=0){
                return new ResponseEntity(null,500,"库存不足",false);
            }
            //在库存足够的情况下，进行秒杀
            //根据商品id和用户id查询秒杀订单表，判断是否购买过了
            QueryWrapper<TbSeckillOrders> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(TbSeckillOrders::getUid,uid)
                            .eq(TbSeckillOrders::getCourseId,id);
            List<TbSeckillOrders> tbSeckillOrders = tbSeckillOrdersMapper.selectList(wrapper);
            if(tbSeckillOrders.size()>0){
                return new ResponseEntity(null,200,"你已购买过商品，不能在购买了",true);
            }
            //根据传过来的用户领取优惠券的表来查询是否用了优惠券下单
            TbDraw newTbDraw = tbDrawMapper.selectByDid(did);
            if(newTbDraw!=null){
                //添加用户领取优惠券的表
                //证明是用优惠券下的单
                flag=true;
            }
            if(flag){
                //是优惠券下的单
               price = this.getDrawOrder(seckillgoods,uid);
            }else{
                //不是优惠券下单
                price=seckillgoods.getCoursePrice();
            }
            //生成订单编号
            long nextId = idWorker.nextId();
            //添加订单
            TbSeckillOrders seckillOrders = new TbSeckillOrders();
            seckillOrders.setId(nextId);
            seckillOrders.setUid(uid);
            seckillOrders.setCourseName(seckillgoods.getCourseName());
            seckillOrders.setCourseId(id);
            seckillOrders.setStartTime(LocalDateTime.now());
            seckillOrders.setCoursePrice(price);
            seckillOrders.setPayStatus(0);
            int insert = tbSeckillOrdersMapper.insert(seckillOrders);
            if(insert>0){
                //减掉库存在存放到redis中
                tbSeckillgoods.setNum(tbSeckillgoods.getNum()-1);
                redisUtils.setBoundHash(seckillKey,id,tbSeckillgoods);
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error("秒杀异常："+e.getMessage());
            return new ResponseEntity(null,500,"秒杀失败",false);
        }
        return new ResponseEntity(null,200,"秒杀成功",true);
    }

    private BigDecimal getDrawOrder(TbSeckillgoods tbSeckillgoods, Integer uid) {
        Double money=0.0;
        Double goodsMoney=tbSeckillgoods.getCoursePrice().doubleValue();
        //根据商品id和用户id来查询用户领取优惠券表
        TbDraw tbDraw = tbDrawMapper.selectId(tbSeckillgoods.getId(),uid);
        Double drawMoney= tbDraw.getPrice().doubleValue();
        //现在时间
        LocalDateTime nowTime = LocalDateTime.now();
        //优惠券使用税时间
        LocalDateTime startTime = tbDraw.getStartTime();
        Duration duration = Duration.between(nowTime, startTime);
        //获取相差的天数
        int toDays =(int) duration.toDays();
        //优惠券计算
        //在小于三天时，优惠券金额不变
        if(toDays<=3){
            money=goodsMoney-drawMoney;
        }else if(toDays<=4 && toDays>3){
            money=goodsMoney-(drawMoney*(1-0.2));
        }else if(toDays<=5 && toDays>4){
            money=goodsMoney-((drawMoney*(1-0.2))*(1-.02));
        }else if(toDays<=6 && toDays>5){
            money=goodsMoney-(((drawMoney*(1-0.2))*(1-0.2))*(1-0.2));
        }
        return new BigDecimal(money);
    }
}
